﻿#include "XmlManager.h"

#include <QDebug>
#include <QTextStream>

bool XmlManager::loadXmlFile(const QString &filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "Failed to open file:" << filePath;
        return false;
    }

    QString errorMsg;
    int errorLine, errorColumn;
    if (!m_domDoc.setContent(&file, &errorMsg, &errorLine, &errorColumn)) {
        file.close();
        qWarning() << QString("XML parse error at line %1, column %2: %3")
                      .arg(errorLine).arg(errorColumn).arg(errorMsg);
        return false;
    }

    file.close();
    m_currentFilePath = filePath;
    return true;
}

bool XmlManager::saveXmlFile(const QString &filePath)
{
    QString savePath = filePath.isEmpty() ? m_currentFilePath : filePath;
    if (savePath.isEmpty()) {
        qWarning() << "No file path specified for saving";
        return false;
    }

    QFile file(savePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning() << "Failed to open file for writing:" << savePath;
        return false;
    }

    QTextStream out(&file);
    m_domDoc.save(out, 4);
    file.close();

    if (!filePath.isEmpty()) {
        m_currentFilePath = filePath;
    }

    return true;
}

QString XmlManager::currentFilePath() const
{
    return m_currentFilePath;
}

bool XmlManager::addElement(const QString &parentPath, const QString &tagName, const QMap<QString, QString> &attributes, const QString &text)
{
    QDomElement parentElement = findElementByPath(parentPath);
    if (parentElement.isNull()) {
        qWarning() << "Parent element not found:" << parentPath;
        return false;
    }

    QDomElement newElement = createElementWithAttributes(tagName, attributes);
    if (!text.isEmpty()) {
        QDomText textNode = m_domDoc.createTextNode(text);
        newElement.appendChild(textNode);
    }

    parentElement.appendChild(newElement);
    return true;
}

bool XmlManager::updateElement(const QString &elementPath, const QMap<QString, QString> &attributes, const QString &text)
{
    QDomElement element = findElementByPath(elementPath);
    if (element.isNull()) {
        qWarning() << "Element not found:" << elementPath;
        return false;
    }

    // 更新属性
    QMap<QString, QString>::const_iterator it;
    for (it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
        element.setAttribute(it.key(), it.value());
    }

    // 更新文本内容
    if (!text.isNull()) {  // 注意: 使用isNull而不是isEmpty来区分空字符串和未提供参数
        // 删除现有文本节点
        QDomNodeList children = element.childNodes();
        for (int i = 0; i < children.count(); ++i) {
            if (children.at(i).isText()) {
                element.removeChild(children.at(i));
                break;
            }
        }

        // 添加新文本节点
        if (!text.isEmpty()) {
            QDomText textNode = m_domDoc.createTextNode(text);
            element.appendChild(textNode);
        }
    }

    return true;
}

bool XmlManager::removeElement(const QString &elementPath)
{
    QDomElement element = findElementByPath(elementPath);
    if (element.isNull()) {
        qWarning() << "Element not found:" << elementPath;
        return false;
    }

    QDomNode parent = element.parentNode();
    if (parent.isNull()) {
        qWarning() << "Cannot remove root element";
        return false;
    }

    parent.removeChild(element);
    return true;
}

QDomElement XmlManager::getElement(const QString &elementPath) const
{
    return findElementByPath(elementPath);
}

QString XmlManager::getElementText(const QString &elementPath) const
{
    QDomElement element = findElementByPath(elementPath);
    if (element.isNull()) {
        return QString();
    }

    // 获取第一个文本子节点
    QDomNodeList children = element.childNodes();
    for (int i = 0; i < children.count(); ++i) {
        if (children.at(i).isText()) {
            return children.at(i).nodeValue();
        }
    }

    return QString();
}

QMap<QString, QString> XmlManager::getElementAttributes(const QString &elementPath) const
{
    QMap<QString, QString> attributes;
    QDomElement element = findElementByPath(elementPath);
    if (element.isNull()) {
        return attributes;
    }

    QDomNamedNodeMap attrMap = element.attributes();
    for (int i = 0; i < attrMap.count(); ++i) {
        QDomAttr attr = attrMap.item(i).toAttr();
        attributes.insert(attr.name(), attr.value());
    }

    return attributes;
}

QList<QDomElement> XmlManager::getChildElements(const QString &parentPath) const
{
    QList<QDomElement> children;
    QDomElement parent = findElementByPath(parentPath);
    if (parent.isNull()) {
        return children;
    }

    QDomNodeList childNodes = parent.childNodes();
    for (int i = 0; i < childNodes.count(); ++i) {
        if (childNodes.at(i).isElement()) {
            children.append(childNodes.at(i).toElement());
        }
    }

    return children;
}

QDomNodeList XmlManager::getElementsByTagName(const QString &tagName)
{
    return m_domDoc.elementsByTagName(tagName);
}

bool XmlManager::readXmlWithStream(const QString &filePath, QList<QMap<QString, QString> > &data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "Failed to open file:" << filePath;
        return false;
    }

    data.clear();
    QXmlStreamReader reader(&file);
    QMap<QString, QString> currentItem;
    QString currentElement;

    while (!reader.atEnd() && !reader.hasError()) {
        QXmlStreamReader::TokenType token = reader.readNext();

        if (token == QXmlStreamReader::StartElement) {
            currentElement = reader.name().toString();

            // 读取属性
            QXmlStreamAttributes attributes = reader.attributes();
            for (const QXmlStreamAttribute &attr : attributes) {
                currentItem[attr.name().toString()] = attr.value().toString();
            }
        } else if (token == QXmlStreamReader::Characters && !reader.isWhitespace()) {
            if (!currentElement.isEmpty()) {
                currentItem[currentElement] = reader.text().toString();
            }
        } else if (token == QXmlStreamReader::EndElement) {
            if (reader.name() == "item") { // 假设每个数据项被<item>包围
                data.append(currentItem);
                currentItem.clear();
            }
            currentElement.clear();
        }
    }

    if (reader.hasError()) {
        qWarning() << "XML error:" << reader.errorString();
        file.close();
        return false;
    }

    file.close();
    return true;
}

bool XmlManager::writeXmlWithStream(const QString &filePath, const QList<QMap<QString, QString> > &data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning() << "Failed to open file for writing:" << filePath;
        return false;
    }

    QXmlStreamWriter writer(&file);
    writer.setAutoFormatting(true);
    writer.setAutoFormattingIndent(2);

    writer.writeStartDocument();
    writer.writeStartElement("data");

    for (const QMap<QString, QString> &item : data) {
        writer.writeStartElement("item");

        QMap<QString, QString>::const_iterator it;
        for (it = item.constBegin(); it != item.constEnd(); ++it) {
            if (it.key().startsWith("@")) { // 属性以@开头
                QString attrName = it.key().mid(1);
                writer.writeAttribute(attrName, it.value());
            } else {
                writer.writeTextElement(it.key(), it.value());
            }
        }

        writer.writeEndElement(); // </item>
    }

    writer.writeEndElement(); // </data>
    writer.writeEndDocument();

    file.close();
    return true;
}

QDomElement XmlManager::getRootElement() const
{
    return m_domDoc.documentElement();
}

QDomElement XmlManager::findElementByPath(const QString &path) const
{
    QStringList pathParts = splitPath(path);
    if (pathParts.isEmpty()) {
        return QDomElement();
    }

    QDomElement currentElement = m_domDoc.documentElement();
    if (currentElement.isNull()) {
        return QDomElement();
    }

    // 检查根元素是否匹配路径的第一部分
    if (currentElement.tagName() != pathParts.first()) {
        return QDomElement();
    }

    pathParts.removeFirst();

    // 遍历路径的其余部分
    for (const QString &part : pathParts) {
        bool found = false;
        QDomNodeList children = currentElement.childNodes();
        for (int i = 0; i < children.count(); ++i) {
            QDomNode node = children.at(i);
            if (node.isElement() && node.toElement().tagName() == part) {
                currentElement = node.toElement();
                found = true;
                break;
            }
        }

        if (!found) {
            return QDomElement();
        }
    }

    return currentElement;
}

QStringList XmlManager::splitPath(const QString &path) const
{
    return path.split('/', QString::SkipEmptyParts);
}

QDomElement XmlManager::createElementWithAttributes(const QString &tagName, const QMap<QString, QString> &attributes)
{
    QDomElement element = m_domDoc.createElement(tagName);

    QMap<QString, QString>::const_iterator it;
    for (it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
        element.setAttribute(it.key(), it.value());
    }

    return element;
}
